import {
  onMounted,
  ref,
  defineComponent,
  reactive,
  onUnmounted,
  computed,
  watch,
  PropType,
  VNode,
  render,
  h
} from "vue";
import { createLayers2, createMap } from "@/utils/ol/maptools";
import {Feature, Map} from "ol";
import "@/styles/map.css"
import {useMineApi} from "@/api/biz/mine";
import {wsg2mapcoor} from "@/utils/gps/maptransform";
import {
  createIrregularGraphicsLayer,
  createLayer2,
  createLineLayer,
  createPoint,
  createPointLayer
} from "@/utils/gps/drawEnclosure";
import pos_icon from '@/assets/gps/pos_icon.png'
import {fenceDecode} from "@/utils/gps/fence";
import {getLastPosition} from "@/api/gps/gps";
import {Geometry, LineString, Point, Circle, Polygon} from "ol/geom";
import SourceVector from "ol/source/Vector";
import LayerVector from "ol/layer/Vector";
import { Fill, Icon, Stroke, Style, Text } from "ol/style";
import moment from "moment";
import car_bluePng from '@/assets/car/car_blue.png'
import { nanoid } from "nanoid";
import {timeFormat} from "@/utils/gps/format";
import {IsPtInPoly} from "@/utils/gps/inside";
import { ElIcon, ElMessage} from "element-plus";
import {CaretLeft, CaretRight, VideoPause, VideoPlay} from "@element-plus/icons-vue";
import {
  calculationStyles,
  lineStyle,
  drawStyleFunc,
  drawLayerStyleFunc,
  enclosureStyleFunc
} from "@/components/map/layerConfig";
import {cloneDeep} from "lodash";
import {boundingExtent, createEmpty} from "ol/extent";
import type { State, NewPath, TravelPath, Record, LocationPoint, Trajectory, AlarmsPosition , StopPosition
  , TrackModel, InitialVehiclePosition, DrawType } from "@/components/map/interface"
import {gpsbus} from "@/utils/gps/event";
import {Device, Geofence} from "@/interface/home";
import Cluster from "ol/source/Cluster";
import useDeviceStore from "@/store/gps/device";
import {storeToRefs} from "pinia";
import Overlay from "ol/Overlay";
import {createPopup} from "@/utils/gps/createPopup";
import mapPopup from "@/components/map-popup";
import {router} from "@/router";
import MapControl from "@/components/map/mapControl.vue";
import {Draw, Modify} from "ol/interaction";
import {Coordinate} from "ol/coordinate";

export default defineComponent({
  name: "CdlMap",
  props: {
    // v-model 记录当前的状态信息
    modelValue: {
      type: Object as PropType<State>,
      default: { currentStep: 0, isPlay: false, speed: 1000 }
    },
    // 控制配置
    control: {
      type: String as PropType<"track" | "trajectory">
    },
    // 绘制矿区
    enclosure: {
      type: Boolean,
      default: false
    },
    // 实时追踪
    realTimeLocation: {
      type: Boolean,
      default: false
    },
    // 历史轨迹
    HistoricalTrajectory:{
      type: Boolean,
      default: false
    },
    active: {
      type: Boolean,
      default: false
    }
  },
  emits: ["update:modelValue"],
  setup(prop, { emit, expose }){
    const mapRef = ref()
    let map: Map

    const deviceStore = useDeviceStore()
    const { checkedDeviceList, checkedDeviceNodeId, checkedDeviceNodeIdList } = storeToRefs(deviceStore)

    // 播放状态
    const state = reactive<State>({
      currentStep: 0,
      isPlay: false,
      speed: 1000,
    })

    // 轨迹记录
    const record: Record = {
      position: [],
      travelPath: [],
      stopPosition: [],
      alarmsPosition: []
    }

    onMounted(()=>{
      initMap()
      initMapEvent()

      initDrawLayer()
      // enclosureLayer = createLayer()
      initEnclosureLayer()

      if(prop.active){
        initCluster()
        gpsbus.on('WS_CMD_POSITIONS', refreshSocketPos)
        gpsbus.on('select', drawCarMarkers)
        gpsbus.on('popup', selectedDevice)
        gpsbus.on('unSelect', removeCarMarkers)
      }
    })

    onUnmounted(()=>{
      clearInterval(trackTimer)
      clearInterval(timer)

      if(prop.active){
        gpsbus.off('WS_CMD_POSITIONS', refreshSocketPos)
        gpsbus.off('select', drawCarMarkers)
        gpsbus.off('popup', selectedDevice)
        gpsbus.off('unSelect', removeCarMarkers)
      }
    })

    watch(() => prop.modelValue, (val) => {
      const { currentStep, isPlay, speed } = val
      state.currentStep = currentStep
      state.isPlay = isPlay
      state.speed = speed
    }, {immediate: true, deep: true})

    watch(state, (value) => {
      emit("update:modelValue", cloneDeep(value))
    })

    // 设备图层
    let devicesClusterLayer: LayerVector<any>
    // 路径图层
    let routeLayer: LayerVector<Feature<LineString>>
    // 停留点图层
    let stopPointLayer: LayerVector<Feature<Point>>
    // 报警点图层
    let alarmPointLayer: LayerVector<Feature<Point>>
    // 一小段路径图层
    let smallRouteLayer: LayerVector<Feature<LineString>>
    // 车和痕迹图层
    let carTracesRouteLayer: LayerVector<Feature<Point>>
    // 矿区图层
    let enclosureLayer: LayerVector<Feature>
    //
    let drawLayer: LayerVector<Feature>

    /**************************** 初始化 ********************************/

    /**
     * 初始化地图
     */
    function initMap() {
      map = createMap(mapRef.value, createLayers2())
    }

    /**
     * 初始化地图事件
     */
    function initMapEvent(){
      if(prop.active){
        map.on('singleclick', drawMapDeviceInfoPopup)
      }
    }

    /**
     * 初始化聚合
     */
    function initCluster(){
      devicesClusterLayer = new LayerVector({
        source: new Cluster({
          distance: 5,
          source: new SourceVector<Feature<Point>>()
        }),
        style: (feature) => calculationStyles(feature, checkedDeviceList.value)
      })
      map.addLayer(devicesClusterLayer)
    }

    /**
     * 初始化数据
     * @param model
     */
    function initData(model?: TrackModel){
      console.log(model)
      if(!model) return
      const { imei, miningId, trajectoryData, initialVehiclePosition } = model

      // 初始化路径图层
      !routeLayer && (routeLayer = createLayer<LineString>())
      // 初始化车图层
      !carTracesRouteLayer && (carTracesRouteLayer = createLayer<Point>())

      // 初始化矿区
      // if(prop.enclosure && miningId) {
      //   enclosureLayer = createLayer()
      //   initEnclosure(miningId)
      // }
      // 初始化历史轨迹
      if(prop.HistoricalTrajectory) {
        !stopPointLayer && (stopPointLayer = createLayer<Point>())
        !alarmPointLayer && (alarmPointLayer = createLayer<Point>())
        if(trajectoryData) initHistoricalTrajectory(trajectoryData)

        adjustTheMapScale()
        // 绑定事件
        // @ts-ignore
        stopPointLayer.on("click", (event)=>{
          console.log(event)
        })
      }
      // 开启实时轨迹
      prop.realTimeLocation && imei && enableRealTimeLocation(imei, initialVehiclePosition)

    }

    /**
     * 创建图层
     */
    function createLayer<T extends Geometry>(){
      const layer = new LayerVector({
        source: new SourceVector<Feature<T>>()
      })
      map.addLayer(layer)
      return layer
    }

    /**
     * 重置资源
     */
    function restResources(){
      const sources = [routeLayer, carTracesRouteLayer, stopPointLayer, alarmPointLayer, enclosureLayer]

      sources.forEach(source =>{
        if(source){
          // @ts-ignore
          source.getSource()?.getFeatures().forEach(feature => source.getSource()?.removeFeature(feature))
        }
      })

      record.position = []
      record.alarmsPosition = []
      record.travelPath = []
      record.stopPosition = []

      handleRefresh()
    }

    // 围栏数据
    let enclosureData: any

    function initEnclosure(miningId: number){
      useMineApi(miningId).then((res) => {
        enclosureData = res.data
        // drawEnclosure()
      })
    }

    function initEnclosureLayer(){
      enclosureLayer = new LayerVector({
        source: new SourceVector<Feature>(),
        // @ts-ignore
        style: enclosureStyleFunc
      })
      map.addLayer(enclosureLayer)
    }

    /**
     * 初始化围栏
     */
    function drawEnclosure() {
      if (enclosureData.latitude && enclosureData.longitude) {
        let minePos = wsg2mapcoor(enclosureData.longitude, enclosureData.latitude)
        enclosureLayer.getSource()?.addFeature(createPoint([minePos.lng as number, minePos.lat as number], pos_icon))
      }
      if (enclosureData.fenceStart) {
        const area: any = fenceDecode(enclosureData.fenceStart)
        enclosureLayer.getSource()?.addFeature(createIrregularGraphicsLayer([area.path.map((e: any) => [e.lng, e.lat])], {
          color: "#3333ff",
          width: 5,
          fill: "rgba(51, 51, 255, 0.5)"
        }))
      }
      if (enclosureData.fenceStart2) {
        const area: any = fenceDecode(enclosureData.fenceStart2)
        enclosureLayer.getSource()?.addFeature(createIrregularGraphicsLayer([area.path.map((e: any) => [e.lng, e.lat])], {
          color: "#3333ff",
          width: 5,
          fill: "rgba(51, 51, 255, 0.5)"
        }))
      }
      if (enclosureData.fenceEnd) {
        const area: any = fenceDecode(enclosureData.fenceEnd)
        enclosureLayer.getSource()?.addFeature(createIrregularGraphicsLayer([area.path.map((e: any) => [e.lng, e.lat])], {
          color: "#00cc00",
          width: 5,
          fill: "rgba(0, 204, 0, 0.5)"
        }))
      }
      if (enclosureData.fenceEnd2) {
        const area: any = fenceDecode(enclosureData.fenceEnd2)
        enclosureLayer.getSource()?.addFeature(createIrregularGraphicsLayer([area.path.map((e: any) => [e.lng, e.lat])], {
          color: "#00cc00",
          width: 5,
          fill: "rgba(0, 204, 0, 0.5)"
        }))
      }
      if (enclosureData.line) {
        const area: any = fenceDecode(enclosureData.line)
        enclosureLayer.getSource()?.addFeature(createLineLayer(area.path.map((e: any) => [e.lng, e.lat]), {
          color: "#ff0000",
          width: 5,
        }))
      }
    }

    /**
     * 初始历史轨迹
     * @param data
     */
    function initHistoricalTrajectory(data: Trajectory){
      // 首次解析数据并存储
      preAnalysis(data)
      // 初始化下车和起始点
      initCarAndBasePoint()
      const { positions, stops, alarms } = data
      // 这里单独处理路径点, 进行分段处理
      const travelPath =  pathSegmentProcessing(positions)

      routeLayer.getSource()?.addFeatures(travelPath.map(item => createNewRoute(item)))
      stopPointLayer.getSource()?.addFeatures(stops.map((item,index) => initStopPoint(item, index)))
      stopPointLayer.getSource()?.addFeatures(alarms.map((item,index) => initAlarmPoint(item, index)))
    }

    /**
     * 轨迹数据预解析
     * @param data
     */
    function preAnalysis(data: Trajectory){
      // 把所有的轨迹点全部合并到总路线里
      record.position.push(...data.positions)

      // 初始化停留点
      record.stopPosition = data.stops.map(item=> {
        return {
          ...wsg2mapcoor(item.longitude, item.latitude),
          residenceTime: timeFormat(item.duration),
          startTime: item.startTime
        }
      })
      // 初始化报警点
      record.alarmsPosition = data.alarms.map(item => {
        return {
          ...wsg2mapcoor(item.longitude, item.latitude),
          startTime: timeFormat(item.occurTime)
        }
      })
    }

    /**
     * 处理路径段数据；
     * 将新传入的轨迹数据，根据速度分成一段一段且连续的路径点；
     * 为优化性能，每次传入的数据并不会立即为其创建新的一段路径点，而是会判断是否匹配上一次路径段的类型，如果是则会将新的数据加在上一次路径段中
     * @param positions 需要被处理的数据
     * @param config {markIndex：总路线最大下标，pathSegment：最后一段路径的下标 }
     * @return travelPath 新的路径段集合
     */
    function pathSegmentProcessing(
        positions: any[],
        config: { markIndex: number, pathSegment: number } = { markIndex: 0, pathSegment: 0 }
    ): NewPath[] {
      let newValue: NewPath[] = [];
      let { markIndex, pathSegment } = config;
      let currentSegment: TravelPath = record.travelPath[pathSegment];
      let prevType: "low" | "normal" | "speeding" | undefined = currentSegment?.type;

      positions.forEach((item, index) => {
        const type = speedType(item.speed);
        const { lng, lat } = wsg2mapcoor(item.longitude, item.latitude);
        if (currentSegment && type === prevType) {
          // 添加到当前路径段
          currentSegment.values.push([lng, lat]);
          currentSegment.endIndex = markIndex;
          // 更新newValue中的对应项
          const segmentInNewValue = newValue.find(seg => seg.id === currentSegment.id);
          if (segmentInNewValue) {
            segmentInNewValue.values.push([lng, lat]);
          }
        } else {
          // 创建新路径段
          const id = nanoid();
          const newSegment: TravelPath = {
            id,
            type,
            startIndex: markIndex,
            endIndex: 0,
            values: [[lng, lat]]
          };
          if (currentSegment) {
            // 如果存在前一个路径段，则复制其最后一个点到新路径段的开始
            newSegment.values.unshift(currentSegment.values[currentSegment.values.length - 1]);
          }
          record.travelPath.push(newSegment);
          newValue.push(newSegment);
          currentSegment = newSegment;
          prevType = type;

          // 更新pathSegment（如果需要的话）
          pathSegment = record.travelPath.length - 1;
        }
        markIndex++;
      });

      return newValue;
    }
    // function pathSegmentProcessing(
    //     positions: any,
    //     config: { markIndex: number, pathSegment: number } = {markIndex: 0, pathSegment: 0}
    // ): NewPath[]{
    //   let newValue: NewPath[] = []
    //   const idArr: string[] = []
    //
    //   let { markIndex, pathSegment } = config
    //   let prevType: "low" | "normal" | "speeding" = record.travelPath[pathSegment]?.type
    //   positions.forEach((item) =>{
    //     const type = speedType(item.speed)
    //     const {lng, lat} = wsg2mapcoor(item.longitude, item.latitude)
    //     if(type === prevType){
    //       record.travelPath[pathSegment].values.push([lng, lat])
    //       record.travelPath[pathSegment].endIndex = markIndex
    //       const index = idArr.indexOf(record.travelPath[pathSegment].id)
    //       if(index !== -1){
    //         newValue[index].values.push([lng, lat])
    //       }else {
    //         newValue.push({
    //           id: record.travelPath[pathSegment].id,
    //           type,
    //           values: [[lng, lat]]
    //         })
    //       }
    //     } else{
    //       prevType = type
    //       const id = nanoid()
    //       record.travelPath.push({
    //         id,
    //         type,
    //         startIndex: markIndex,
    //         endIndex: 0,
    //         values: [[lng, lat]]
    //       })
    //       newValue.push({
    //         id,
    //         type,
    //         values: [[lng, lat]]
    //       })
    //       pathSegment = record.travelPath.length - 1
    //       if(pathSegment){
    //         const lastValues = record.travelPath[pathSegment - 1].values
    //         record.travelPath[pathSegment].values.unshift(lastValues[lastValues.length -1])
    //         newValue[newValue.length - 1].values.unshift(lastValues[lastValues.length -1])
    //       }
    //       idArr.push(id)
    //     }
    //     markIndex ++
    //   })
    //   return newValue
    // }

    function speedType(speed: number){
      const s = speed * 1.852
      if(s < 20){
        return "low"
      }else if(s < 80){
        return "normal"
      }else {
        return "speeding"
      }
    }

    /**
     * 创建特征
     * @param geometry 几何对象
     * @param style 样式
     * @param polylineId Id
     * @param properties Id
     */
    function createFeature<T extends Geometry>(geometry: T, style?: Style, polylineId?: string, properties: any = {}){
      let feature = new Feature(geometry)
      polylineId && feature.setId(polylineId)
      properties && feature.setProperties(properties)
      style && feature.setStyle(style)
      return feature
    }

    /**
     * 创建一段路径点
     * @param travelPath 路径点集合
     */
    function createNewRoute({id, type, values}: NewPath): Feature<LineString>{
      const c = lineStyle[type]
      const style: Style = new Style({
        stroke: new Stroke({
          color: c.stroke.color,
          width: c.stroke.width
        })
      })
      return createFeature(new LineString(values), style, id )
    }

    /**
     * 初始化停留点集合
     * @param data
     * @param index
     */
    function initStopPoint(data: LocationPoint, index: number): Feature<Point>{
      const style: Style = new Style({
        image: new Icon({
          // 定义图标锚点
          anchor: [0.5, 1],
          scale: 0.5,
          src: "https://gps.1688wxq.com/gps/icon/points/" + (index + 1)
        })
      })
      const {lng, lat} = wsg2mapcoor(data.longitude, data.latitude)
      return createFeature(new Point([lng, lat]), style)
    }
    /**
     * 初始化报警点集合
     * @param data
     * @param index
     */
    function initAlarmPoint(data: LocationPoint, index: number): Feature<Point>{
      const style: Style = new Style({
        image: new Icon({
          // 定义图标锚点
          anchor: [0.5, 1],
          scale: 0.5,
          src: "https://gps.1688wxq.com/gps/icon/alarm/" + (index + 1)
        })
      })
      const {lng, lat} = wsg2mapcoor(data.longitude, data.latitude)
      return createFeature(new Point([lng, lat]), style)
    }

    /**
     * 初始化车辆、起点和终点
     */
    function initCarAndBasePoint(){
      const {latitude, longitude, direction} = record.position[0]
      const style: Style = new Style({
        image: new Icon({
          anchor: [0.5, 0.5],
          scale: 0.8,
          src: car_bluePng,
          rotation: (Math.PI / 180) * (direction % 360)
        })
      })
      const {lng, lat} = wsg2mapcoor(longitude, latitude)
      const carFeature = createFeature(new Point([lng, lat]), style, "car")
      carTracesRouteLayer.getSource()?.addFeature(carFeature)
    }

    const totalTime = ref(0)
    const formatTime = computed(()=>{
      return moment.utc(moment.duration(totalTime.value, "seconds").asMilliseconds()).format("HH:mm:ss")
    })
    // 侦听器
    let trackTimer: any
    let timer: any
    /**
     * 开启实时位置获取
     */
    function enableRealTimeLocation(imei: string, data: InitialVehiclePosition){
      let time: undefined | number = undefined
      // 判断一下前面有没有获取过历史轨迹, 如果有就先初始化下time并创建一个图层，否则先获取最新的位置
      if(prop.HistoricalTrajectory){

      }else {
        getNearestLocation(imei)
        // 初始化第一个位置
        record.position[0] = data
        initCarAndBasePoint()
      }
      trackTimer = setInterval(() => getNearestLocation(imei), 5000)
      timer = setInterval(()=>{
        totalTime.value ++
      }, 1000)

      /**
       * 获取最近的位置
       */
      function getNearestLocation(imei: string){
        console.log("获取位置")
        getLastPosition({
          imeis: imei,
          lastQueryPositionTime: time
        }).then((res) => {
          const data: any = res.data
          if (!data.length) return
          // 有数据再更新时间
          time = moment().valueOf()
          // 处理新的数据并保存, 这样每次只需要画新的数据，而不用将整个图层全画一遍
          let newTravelPath = pathSegmentProcessing(data, {
            markIndex: record.position.length,
            pathSegment: record.travelPath.length
          })

          // 更新总数据
          record.position.push(...data)

          routeLayer.getSource()?.addFeatures(newTravelPath.map(item => createNewRoute(item)))
          const lastPosition = record.position[record.position.length - 1]
          const {lng, lat} = wsg2mapcoor(lastPosition.longitude, lastPosition.latitude)
          updateVehicleLocation([lng, lat], lastPosition.direction)

        })
      }
    }

    /**
     * 计算轨迹并调整视图以适应边界
     */
    function adjustTheMapScale(){
      const lines = routeLayer.getSource()?.getFeatures()
      if(!lines) return
      // @ts-ignore
      const coordinates = lines.reduce((extent, line) => {
        // @ts-ignore
        return extent? extent.concat(line.getGeometry()?.getCoordinates()) : line.getGeometry()?.getCoordinates()
      }, [] as any[])
      const extent = boundingExtent(coordinates as any)
      if (extent) {
        map.getView().fit(extent, { duration: 500, padding: [50, 50, 50, 50]});
      }
    }


    /**************************** 外部调用及被动接收状态 ********************************/

    /**
     * 车辆信息变更通知
     * @param data
     */
    function positionsCome(data: any){
      const { id , position } = data
    }

    /**
     * 设备被行选中的通知
     * @param nodeId
     */
    function selectedDevice(nodeId: string){
      const deviceData = checkedDeviceList.value[nodeId]
      const { lng, lat } = wsg2mapcoor(deviceData?.longitude, deviceData?.latitude)
      setMapCenter(lng, lat )
      if (!popup) openPopup([lng, lat])
      else movePopup([lng, lat])
    }

    /**
     * 设备被单选中的通知
     * @param devices
     */
    function drawCarMarkers(devices: Device[]){
      const features = devices.map(device =>{
        const { lng, lat } = wsg2mapcoor(device.longitude, device.latitude)
        return createFeature(new Point([lng, lat]), undefined, device.nodeId)
      })
      // @ts-ignore
      devicesClusterLayer.getSource()?.getSource()?.addFeatures(features)
    }

    /**
     * 设备被取消选中的通知
     * @param nodeId
     */
    function removeCarMarkers(nodeId: string[] | string){
      if (Array.isArray(nodeId)) {
        for (let i = 0; i < nodeId.length; i++) {
          const feature = getFeature(nodeId[0])
          if (feature) {
            removeFeature(feature)
          }
        }
      } else {
        const feature = getFeature(nodeId)
        if (feature) {
          removeFeature(feature)
        }
        if (checkedDeviceNodeId.value === nodeId && popup) {
          closePopup()
        }
      }
    }

    /**
     * 围栏被选中
     * @param data
     */
    function drawEnclosures(data: Geofence[]){
      const arr: Feature<Geometry>[] = []
      // let coordinates: Coordinate[] = []
      data.forEach(enclosure =>{
        const { type, area, nodeId, name } = enclosure
        const areaData = JSON.parse(area)
        switch (type){
          case "Circle":
            const circle = new Circle(areaData.center, areaData.radius)
            arr.push(createFeature(circle, undefined, nodeId, {
              name
            }))
            // coordinates.push(...getCirclePoints(circle))
            break
          case "Polygon":
            arr.push(createFeature(new Polygon(areaData.coordinates), undefined, nodeId,{
              name
            }))
            // coordinates.push(...areaData.coordinates[0])
            break
          default:
            break
        }
      })
      enclosureLayer.getSource()?.addFeatures(arr)
      // adaptToBoundaries(coordinates)
    }

    /**
     * 围栏取消选中
     * @param nodeId
     */
    function removeEnclosure(nodeId: string){
      const feature = enclosureLayer.getSource()?.getFeatureById(nodeId)
      if (feature) {
        enclosureLayer.getSource()?.removeFeature(feature)
      }
    }

    function selectEnclosure(nodeId:string){
      const feature = enclosureLayer.getSource()?.getFeatureById(nodeId)
      const geometry = feature?.getGeometry()
      if(!geometry) return;
      let coordinates: Coordinate[] = []
      switch (geometry.getType()){
        case "Circle":
          coordinates = getCirclePoints(geometry as Circle)
          break
        case "Polygon":
          coordinates = (geometry as Polygon).getCoordinates()[0]
          break
      }
      adaptToBoundaries(coordinates)
    }

    /** ********************************** map绘制 **************************** **/
    // 绘制对象
    let draw: Draw
    // 交互对象
    let modify: Modify
    // 绘制数据
    const drawData = ref()

    /**
     * 初始化drawLayer
     */
    function initDrawLayer(){
      if(!drawLayer){
        drawLayer = new LayerVector<Feature>({
          source: new SourceVector({
            wrapX: false
          }),
          // @ts-ignore
          style: drawLayerStyleFunc
        })
        map.addLayer(drawLayer)

        modify = new Modify({
          source: drawLayer.getSource()!,
          pixelTolerance: 10,
        });
        map.addInteraction(modify)
      }
    }

    /**
     * 创建一个几何图形
     * @param id
     * @param type
     * @param data
     */
    function createGeometry({id, type, data}: {id: string, type: DrawType, data: string}){
      console.log(type, data)
      const geometryData = JSON.parse(data)
      switch (type){
        case "Circle":
          drawLayer.getSource()?.addFeature(createFeature(new Circle(geometryData.center, geometryData.radius)
              , undefined, id))
          break
        case "Polygon":
          drawLayer.getSource()?.addFeature(createFeature(new Polygon(geometryData.coordinates)
              , undefined, id))
          break
      }

      modify.setActive(true)

    }

    /**
     * 清空后再绘制
     * @param type
     */
    function clearDraw(type: DrawType){
      clearEnclosure()
      drawInteraction(type)
    }

    /**
     * 绘制交互
     * @param type
     */
    function drawInteraction(type: DrawType){
      switch (type){
        case "Circle":
          drawFea(map, drawLayer, type)
          break
        case "Point":
          drawFea(map, drawLayer, type)
          break
        case "Polygon":
          drawFea(map, drawLayer, type)
          break
      }
    }

    /**
     * 绘制方法
     * @param map
     * @param layer
     * @param type
     */
    function drawFea(map, layer, type) {
      // 创建绘图工具
      draw = new Draw({
        type,
        source: drawLayer.getSource()!,
        // @ts-ignore
        // style: drawStyleFunc
      });

      draw.on('drawend', (event) => {
        console.log("开启交互",event)
        map.removeInteraction(draw);
        // 绘制完成后，直接可以拖动图形
        modify.setActive(true); // 启用修改功能
      });
      // 给地图添加绘图交互
      map.addInteraction(draw);
    }

    /**
     * 清除已绘制的围栏
     */
    function clearEnclosure(){
      modify.setActive(false)
      map.removeInteraction(draw);
      if(drawLayer){
        const features = drawLayer.getSource()?.getFeatures()
        console.log(features)
        features?.forEach(item => drawLayer.getSource()?.removeFeature(item))
      }
    }

    function getDrawData(){
      drawData.value = drawLayer.getSource()?.getFeatures()
    }

    /** ********************************** 小车状态及位置控制 **************************** **/
    let popup
    let mapOverlay
    const popupRef = ref()

    const currenDeviceInfo = computed(() => {
      return checkedDeviceList.value[checkedDeviceNodeId.value]
    })

    /**
     * 适应边界
     */
    function adaptToBoundaries(coordinates: Coordinate[]){
      console.log(coordinates)
      const extent = boundingExtent(coordinates)
      if (extent) {
        map.getView().fit(extent, { duration: 500, padding: [50, 50, 50, 50]});
      }
    }

    /**
     * 计算圆边缘四个点
     * @param circle
     */
    function getCirclePoints(circle: Circle) {
      const extent = circle.getExtent();
      const topLeft = [extent[0], extent[3]];
      const topRight = [extent[2], extent[3]];
      const bottomRight = [extent[2], extent[1]];
      const bottomLeft = [extent[0], extent[1]];
      return [topLeft, topRight, bottomRight, bottomLeft];
    }

    /**
     * 通过id获取指定的Feature
     * @param id
     */
    function getFeature(id: string): Feature | null {
      // @ts-ignore
      return devicesClusterLayer.getSource()?.getSource()?.getFeatureById(id)
    }

    /**
     * 移除指定的Feature
     * @param marker
     */
    function removeFeature(marker: Feature) {
      // @ts-ignore
      devicesClusterLayer.getSource()?.getSource()?.removeFeature(marker)
    }

    /**
     * 重绘小车位置
     * @param data
     * @param nodeId
     */
    function redrawPosition(nodeId: string, data) {
      const { lng, lat } = wsg2mapcoor(data.longitude, data.latitude)
      const feature = getFeature(nodeId)
      if(!feature) return
      // @ts-ignore
      feature.getGeometry()?.setCoordinates([lng, lat]);
    }

    /**
     * 点击marker的回调，绘制地图上的设备信息弹窗
     */
    function drawMapDeviceInfoPopup(e) {
      const feature = map.forEachFeatureAtPixel(e.pixel, (feature) => feature)
      if (feature) {
        const features = feature.get('features')
        if(!features) return
        const size = features.length
        if (size === 1) {
          checkedDeviceNodeId.value = features[0].getId()
          openPopup(features[0].getGeometry().getCoordinates())
        } else if (features.length > 1) {
          let nodeId = features[0].getId()
          const deviceData = checkedDeviceList.value[nodeId]
          const endPos = wsg2mapcoor(deviceData?.longitude, deviceData?.latitude)
          map.getView().animate({
            center: [endPos.lng, endPos.lat],
            zoom: 16,
            duration: 200
          })
        }
      } else {
        closePopup()
      }
    }

    /**
     * 创建弹窗
     * @param pos
     */
    function openPopup(pos: number[]) {
      const popupVNode: VNode = createPopup(
          {
            header: () => h('div'),
            default: (close) =>
                h(mapPopup, {
                  device: currenDeviceInfo.value,
                  onClose: () => closePopup(),
                  // onCommand: () => sendCmdRef.value.init(checkedDeviceNodeId.value),
                  onJumpPage: (name: string) => gpsbus.emit('switchMenu', name),
                  // onWarning: () => devWarningRef.value.init(checkedDeviceNodeId.value),
                  onJumpWaybill: () =>
                      router.push({
                        path: '/dashboard/waybillMonitor',
                        query: {
                          sysOrgId: currenDeviceInfo.value.companyId,
                          id: currenDeviceInfo.value.attribute.waybillId
                        }
                      })
                })
          },
          {
            target: popupRef.value,
            mask: false,
            rootElStyle: 'position: static; transform: none; margin: 0;'
          }
      )

      let overlay = new Overlay({
        element: popupVNode.el as any,
        positioning: 'bottom-center',
        stopEvent: true,
        offset: [0, -30]
      })
      map.addOverlay(overlay)
      overlay.setPosition(pos)
      popup = popupVNode
      mapOverlay = overlay
    }

    /**
     * 移动弹窗
     * @param pos
     */
    function movePopup(pos: number[]) {
      if (mapOverlay) {
        mapOverlay.setPosition(pos)
      }
    }

    /**
     * 关闭弹出层
     */
    function closePopup() {
      render(null, popupRef.value)
      popupRef.value.remove()
      popup = null
      mapOverlay = null
    }

    /**
     * 设置地图中心点
     * @param longitude
     * @param latitude
     */
    function setMapCenter(longitude: number, latitude: number) {
      map.getView().animate({
        center: [longitude, latitude],
        duration: 500
      })
    }

    /**
     * 车辆信息变更处理事件
     * @param data
     */
    function refreshSocketPos(data) {
      const { imei, position } = data
      const nodeId = "d-" + imei
      if (checkedDeviceNodeId.value === nodeId && popup) {
        const { lng, lat } = wsg2mapcoor(position.longitude, position.latitude)
        movePopup([lng, lat])
        map.getView().animate({
          center: [lng, lat],
          duration: 100
        })
      }
      if (devicesClusterLayer && checkedDeviceNodeIdList.value.includes(nodeId)) {
        redrawPosition(nodeId, position)
      }
    }

    /** ********************************** 媒体相关 **************************** **/

    // 播放速率
    const playSpeed = ref<number>(500)
    // 进度
    const percentage = ref<number>(0)


    // 当前位置以及方向
    const currentPosition = computed(()=>{
      return { position: record.travelPath[state.currentStep], rotation: record.position[state.currentStep].course}
    })
    // 当前车速
    const currentCarSpeed = computed(()=>{
      return record.position[state.currentStep].speed
    })
    // 媒体相关
    const innerRef = ref()
    // 已播放进度
    const playedProgress = computed(() => {
      return `width: ${percentage.value}%`
    })
    // 已加载进度
    const loadedProgress = computed(() => {
      return `width: ${100}%`
    })
    // 进度条实际宽度
    const progressBarWidth = computed(() => {
      return innerRef.value?.offsetWidth
    })

    watch(()=> state.currentStep, ()=>{
      cruiseEvent()
    })

    /**
     * 更新车辆位置
     * @param location 位置
     * @param direction 方向
     * @constructor
     */
    function updateVehicleLocation(location: [number, number], direction: number){
      const feature = carTracesRouteLayer.getSource()?.getFeatureById("car")
      if(feature){
        feature.getGeometry()?.setCoordinates(location);
        (feature.getStyle() as Style).getImage()?.setRotation((Math.PI / 180) * (direction % 360));
      }
    }

    /**
     * 小车巡航事件
     */
    function cruiseEvent() {
      const currentPosition = record.position[state.currentStep]
      const {lng, lat} = wsg2mapcoor(currentPosition.longitude, currentPosition.latitude)
      updateVehicleLocation([lng, lat], currentPosition.direction)
      // isInside([lng, lat])
      percentage.value = parseFloat(((state.currentStep / record.position.length) * 100).toFixed(1))
    }
    let stepInterval: any
    /**
     * 开始播放
     */
    function handlePlay() {
      console.log("开始播放");
      if (record.position.length === 0) return ElMessage.warning('无法播放')
      state.isPlay = true
      stepInterval = setInterval(() => {
        console.log(state.currentStep)
        if (state.currentStep < record.position.length - 1) {
          state.currentStep ++
        } else {
          percentage.value = 100
          handlePause()
        }
      }, state.speed)
    }

    /**
     * 暂停播放
     */
    function handlePause() {
      console.log("暂停");
      state.isPlay = false
      clearInterval(stepInterval)
    }

    /**
     * 重置播放
     */
    function handleRefresh() {
      handlePause()
      state.currentStep = 0
      percentage.value = 0
    }

    /**
     * 上一步
     */
    function handlePrev() {
      if (state.currentStep > 0 && state.currentStep <= record.position.length) state.currentStep --
    }

    /**
     * 下一步
     */
    function handleNext() {
      if (state.currentStep < record.position.length) state.currentStep ++

    }

    /**
     * 判断小车是否在可视范围内
     * @param position
     */
    function isInside(position: any) {
      let isArr: any = map.getView().calculateExtent(map.getSize())
      if (
          !IsPtInPoly(position[0], position[1], [
            {longitude: isArr[2], latitude: isArr[1]},
            {longitude: isArr[0], latitude: isArr[1]},
            {longitude: isArr[0], latitude: isArr[3]},
            {longitude: isArr[2], latitude: isArr[3]}
          ])
      )
        map.getView().setCenter(position)
    }

    expose({
      initData,
      restResources,
      handlePause,
      handlePlay,
      drawEnclosures
    })

    /**
     * 控制器
     */
    function controlPlugin(){
      switch (prop.control) {
        case "track":
          return <div class="time">
            <p>已追踪时长<span>{formatTime.value}</span></p>
          </div>
        case "trajectory":
          return <div class="tool-window">
            <div class={`btn ${state.currentStep === 0 ? "disabled" : ""}`}
                 onClick={handlePrev}>
              <ElIcon size={22} color="rgb(64, 158, 255)"><CaretLeft></CaretLeft></ElIcon>
            </div>
            {
              !state.isPlay ? <div class="btn" onClick={handlePlay}>
                    <ElIcon size={22} color="rgb(64, 158, 255)"><VideoPlay></VideoPlay></ElIcon>
                  </div>
                  :
                  <div class="btn" onClick={handlePause}>
                    <ElIcon size={22} color="rgb(64, 158, 255)"><VideoPause></VideoPause></ElIcon>
                  </div>
            }
            <div
                class={`btn ${state.currentStep === record.position.length - 1 || record.position.length === 0 ? "disabled" : ""}`}
                onClick={handleNext}>
              <ElIcon size={22} color="rgb(64, 158, 255)"><CaretRight></CaretRight></ElIcon>
            </div>
            {/*<ElButton type="danger" icon={Refresh} onClick={handleRefresh}></ElButton>*/}
            <div class="player_progress">
              <div ref={innerRef} class="player_progress__inner">
                <div class="player_progress__load" style={loadedProgress.value}></div>
                <div class="player_progress__play" style={playedProgress.value}>
                  <i ref="dotRef" class="player_progress__dot"></i>
                </div>
              </div>
            </div>
          </div>
        default:
          return
      }
    }

    return () => <div class="cdl-map">
      <div ref={mapRef} class="map-fence"></div>
      <div ref={popupRef}></div>
      <MapControl // @ts-ignore
                  enclosure={drawData.value}
                  onCreateGeometry={createGeometry}
                  onClearDraw={clearDraw}
                  onGetDrawData={getDrawData}
                  onCloseDraw={clearEnclosure}
                  onDrawEnclosure={drawEnclosures}
                  onRemoveEnclosure={removeEnclosure}
                  onSelectEnclosure={selectEnclosure}></MapControl>
      {controlPlugin()}
    </div>
  }
})
